/* promise原理代码*/
//promise有三种状态，等待pending，成功fulfilled，失败rejected
const PENDING ='pending';//等待
const FULFILLED ='fulfilled';//成功
const REJECTED ='rejected';//失败

class MyPromise {  //Promise 就是一个类
constructor(executor) { //定义一个执行器，需要接受两个参数，成功回调resolve，失败回调reject,并且立即执行
  try {//捕获执行器错误
	executor(this.resolve, this.reject)
  }catch(e) {//错误时传递错误
	this.reject(e);
  }

}
status = PENDING; //promise状态  默认状态是等待panding
value = undefined;// 成功的值  默认undefined
reason = undefined;// 失败的值  默认undefined
successCallback = [];//成功回调 数组可以同时存储多个回调函数
failCallback = [];// 失败回调 数组可以同时存储多个回调函数

resolve = value =>{// 执行器中的resolve
  if(this.status !== PENDING ) return ;// 如果状态不是等待,阻止程序向下执行
  this.status = FULFILLED; //将状态更改为成功
  this.value = value;// 保存成功之后的值
  // 判断成功回调是否存在 如果存在就调用
  while(this.successCallback.length){
	this.successCallback.shift()()
  }
}
reject = reson =>{// 执行器中的rejected
  if(this.status !== PENDING ) return ;// 如果状态不是等待,阻止程序向下执行
  this.status = REJECTED; //将状态更改为失败
  this.reason = reason;// 保存失败之后的值
  // 判断失败回调是否存在 如果存在就调用
  while(this.failCallback.length){
	this.failCallback.shift()()
  }
}
then (successCallback, failCallback) { //then方法接收成功回调和失败回调
  successCallback = successCallback ? successCallback : value => value;//当没有传递成功回调
  failCallback = failCallback? failCallback: reason => { throw reason };//当没有传递失败回调
  let promise2 = new MyPromise((resolve, reject)=>{
	// 判断状态
	if(this.status === FULFILLED){//成功  //同步操作
	  setTimeout(() => {//异步代码 才能够获取promise2
		try{  //捕获错误
		  let x = successCallback(this.value) //将成功的值传递给回调函数
		  // 判断x的值是普通值还是promise对象
		  //如果是普通值,直接调用resolve
		  //如果是promise对象,查看promise对象返回的结果
		  //再根据promise对象返回的结果,决定调用resolve还是调用reject
		  resolvePromise(promise2, x, resolve, reject)
		}catch(e){
		  reject(e);
		}
	  }, 0)
	}else if(this.status === REJECTED){//失败  //同步操作
	  setTimeout(() => {//异步代码 才能够获取promise2
		try{  //捕获错误
		  let x = failCallback(this.reason)  //将失败原因传递给回调函数
		  // 判断x的值是普通值还是promise对象
		  //如果是普通值,直接调用resolve
		  //如果是promise对象,查看promise对象返回的结果
		  //再根据promise对象返回的结果,决定调用resolve还是调用reject
		  resolvePromise(promise2, x, resolve, reject)
		}catch(e){
		  reject(e);
		}
	  }, 0)
	}else { //等待状态  将成功回调和失败回调存储起来  //异步操作
	  this.successCallback.push(() =>{
		setTimeout(() => {//异步代码 才能够获取promise2
		  try{  //捕获错误
			let x = successCallback(this.value) //将成功的值传递给回调函数
			// 判断x的值是普通值还是promise对象
			//如果是普通值,直接调用resolve
			//如果是promise对象,查看promise对象返回的结果
			//再根据promise对象返回的结果,决定调用resolve还是调用reject
			resolvePromise(promise2, x, resolve, reject)
		  }catch(e){
			reject(e);
		  }
		}, 0)
	  });
	  this.failCallback.push(() => {
		setTimeout(() => {//异步代码 才能够获取promise2
		  try{  //捕获错误
			let x = failCallback(this.reason)  //将失败原因传递给回调函数
			// 判断x的值是普通值还是promise对象
			//如果是普通值,直接调用resolve
			//如果是promise对象,查看promise对象返回的结果
			//再根据promise对象返回的结果,决定调用resolve还是调用reject
			resolvePromise(promise2, x, resolve, reject)
		  }catch(e){
			reject(e);
		  }
		}, 0)
	  });
	}
  });
  return promise2;
}
finally (callback) => {//1.finally方法无论promise成功还是失败都会执行一次；2.finally后面可以继续then链式掉用
	return this.then(value => { //then知道promise状态&then返回promise对象
		return MyPromise.resolve(callback()).then(() => value) //执行callback，不管返回值是什么，都转成promise，然后执行promise
	}, reason => {
		return MyPromise.resolve(callback()).then(() => {throw reason})
	})
}
catch (failCallback) { //catch只接收失败回调
	return this.then(undefined, failCallback)
}
// all在调用的时候是Promise.all(),所以all是静态方法
// all等到所有方法成功执行完毕之后返回一个具有所有返回值的数组
// all中如果有一个执行失败，直接进入reject
static all (array) { //静态all方法
  let result = [];
  let index = 0;
  return new MyPromise((resolve, reject) => {
	function addData(key, value) {  //存储结果
	  result[key] = value;
	  index++;
	  if(index === array.length){ //all中可能有异步操作，需要保证所有异步操作都执行完了
		resolve(result);
	  }
	}
	for(let i=0; i<array.length; i++){
	  let current = array[i];
	  if(current instanceof MyPromise){//current的值是promise对象
		current.then(value => addData(i, value), reason => reject(reason))
	  }else{//current的值是普通值
		addData(i, array[i]);
	  }
	}
  })
}

// resolve静态方法，如果是promise对象，直接返回，如果是普通值，需要转成promise对象
static resolve (value) {
  if(value instanceof MyPromise) return value;
  return new MyPromise(resolve => resolve(value));
}

//reject静态方法 传入失败的原因， 返回一个肯定失败的promise对象
static reject(reason) {
  return new MyPromise((resolve, reject) =>  reject(reason))
}

}

function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x){ //判断是否自己返回自己
  //阻止代码向下执行,因为promise 对象被循环调用
  return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise) {  //x的值是promise对象
  x.then(resolve, reject);
} else { //x的值是普通值
  resolve(x);
}
}

module.exports = MyPromise //导出类MyPromise